package visualization.ganeatgeneric;


import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.text.DecimalFormat;
import java.text.NumberFormat;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import optimizers.ganeatgeneric.Individual;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.AbstractCategoryItemLabelGenerator;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.XYItemLabelGenerator;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.TextAnchor;

import util.MyUtil;

public class PlotIndividualHistory extends JPanel implements ActionListener,
		WindowListener, ChangeListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Individual indiv;
	private Individual[] indivs;
	private JPanel graphPanel = null;
	private JPanel[] graphs;
	private JPanel showingPanel;

	/**
	 * Constructs the demo application.
	 * 
	 * @param title
	 *            the frame title.
	 */
	/*
	 * public PlotExpData(final String title) { super(title); XYDataset dataset
	 * = createSampleDataset(); JFreeChart chart =
	 * ChartFactory.createXYLineChart( title, "Time", "Expression Level",
	 * dataset, PlotOrientation.VERTICAL, true, false, false ); XYPlot plot =
	 * (XYPlot) chart.getPlot(); //XYLineAndShapeRenderer renderer = new
	 * XYLineAndShapeRenderer(); //renderer.setSeriesLinesVisible(0, true);
	 * //renderer.setSeriesShapesVisible(0, true);
	 * //renderer.setSeriesLinesVisible(1, false);
	 * //renderer.setSeriesShapesVisible(1, true); //plot.setRenderer(renderer);
	 * final ChartPanel chartPanel = new ChartPanel(chart);
	 * //chartPanel.setPreferredSize(new java.awt.Dimension(800, 800));
	 * setContentPane(chartPanel); }
	 */
	public PlotIndividualHistory(final String title, Individual indiv) {
		this.indiv = indiv;

		setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));

		double[][] expData = new double[1][indiv.generationIndex + 1];
		Individual tmp = indiv;
		Individual currentIndiv = null;
		JPanel currentPanel = null;
		String[] labels = new String[indiv.generationIndex + 1];
		indivs = new Individual[indiv.generationIndex + 1];
		graphPanel = new JPanel();
		graphPanel.setSize(250, 250);
		add(graphPanel);

		graphs = new JPanel[indiv.generationIndex + 1];

		do {
			int start = 0;
			if (tmp != null) {
				start = tmp.generationIndex + 1;
			}
			if (currentIndiv != null) {
				for (int i = start; i <= currentIndiv.generationIndex; i++) {
					indivs[i] = currentIndiv;
					expData[0][i] = indivs[i].fitnessResult.finalResult();
					graphs[i] = currentPanel;
				}
				if (tmp != null) {
					labels[tmp.generationIndex + 1] = MyUtil
							.getShortMutationString(indivs[tmp.generationIndex + 1].mutationInfo);
				}
			}
			if (tmp == null) {
				break;
			}
			currentIndiv = tmp;
			currentPanel = new JPanel();
			graphPanel.add(currentPanel);
			currentPanel.add(tmp.getOligoSystem().getVisualization(250, 250));
			currentPanel.setVisible(false);
			double parent1Fitness = (tmp.parent1 == null ? Double.MIN_VALUE
					: tmp.parent1.fitnessResult.finalResult());
			double parent2Fitness = (tmp.parent2 == null ? Double.MIN_VALUE
					: tmp.parent2.fitnessResult.finalResult());
			if (parent1Fitness > parent2Fitness) {
				tmp = tmp.parent1;
			} else {
				tmp = tmp.parent2;
			}
		} while (true);

		graphs[0].setVisible(true);
		showingPanel = graphs[0];

		// Create the label.
		JLabel sliderLabel = new JLabel("Generation", JLabel.CENTER);
		sliderLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

		// Create the slider.
		JSlider generationSlider = new JSlider(JSlider.HORIZONTAL, 0,
				indiv.generationIndex, 0);

		generationSlider.addChangeListener(this);

		// Turn on labels at major tick marks.

		generationSlider.setMajorTickSpacing(10);
		generationSlider.setMinorTickSpacing(1);
		generationSlider.setPaintTicks(true);
		generationSlider.setPaintLabels(true);
		generationSlider
				.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
		Font font = new Font("Serif", Font.ITALIC, 15);
		generationSlider.setFont(font);
		add(sliderLabel);
		add(generationSlider);

		// super(title);
		XYDataset dataset = createSampleDataset(expData, 0, 1,
				new String[] { "Fitness" });
		final JFreeChart chart = ChartFactory.createXYLineChart(title,
				"Generation", "Fitness", dataset, PlotOrientation.VERTICAL,
				true, false, false);
		final ChartPanel chartPanel = new ChartPanel(chart);
		XYPlot categoryPlot = (XYPlot) chart.getPlot();

		XYLineAndShapeRenderer lineAndShapeRenderer = (XYLineAndShapeRenderer) categoryPlot
				.getRenderer();
		ItemLabelPosition position = new ItemLabelPosition(
				ItemLabelAnchor.CENTER, TextAnchor.BASELINE_LEFT,
				TextAnchor.BASELINE_LEFT, -Math.PI / 2);
		lineAndShapeRenderer.setBasePositiveItemLabelPosition(position);
		lineAndShapeRenderer.setBaseNegativeItemLabelPosition(position);

		lineAndShapeRenderer
				.setBaseItemLabelGenerator(new CustomLabelGenerator(title,
						new DecimalFormat("#.#"), labels));

		lineAndShapeRenderer.setBaseItemLabelsVisible(true);
		chartPanel.setPreferredSize(new java.awt.Dimension(1000, 400));
		/*
		 * chartPanel.addMouseMotionListener(new MouseMotionListener() {
		 * 
		 * @Override public void mouseMoved(MouseEvent chartMouseEvent) { int
		 * mouseX = chartMouseEvent.getX(); int mouseY = chartMouseEvent.getY();
		 * 
		 * Point2D p = chartPanel.translateScreenToJava2D(new Point( mouseX,
		 * mouseY)); XYPlot plot = (XYPlot) chart.getPlot(); Rectangle2D
		 * plotArea = chartPanel.getScreenDataArea(); ValueAxis domainAxis =
		 * plot.getDomainAxis(); RectangleEdge domainAxisEdge =
		 * plot.getDomainAxisEdge(); ValueAxis rangeAxis = plot.getRangeAxis();
		 * RectangleEdge rangeAxisEdge = plot.getRangeAxisEdge(); double chartX
		 * = domainAxis.java2DToValue(p.getX(), plotArea, domainAxisEdge);
		 * double chartY = rangeAxis.java2DToValue(p.getY(), plotArea,
		 * rangeAxisEdge); DecimalFormatSymbols dfs = new
		 * DecimalFormatSymbols(); dfs.setDecimalSeparator('.'); NumberFormat f
		 * = new DecimalFormat("#00.00", dfs);
		 * 
		 * System.out.println("mouseX:" + f.format(new Double(chartX)));
		 * System.out.println("mouseY:" + f.format(new Double(chartY)));
		 * 
		 * }
		 * 
		 * @Override public void mouseDragged(MouseEvent arg0) { // TODO
		 * Auto-generated method stub
		 * 
		 * } });
		 */
		// setContentPane(chartPanel);
		this.add(chartPanel);
	}

	private XYDataset createSampleDataset(double expData[][], double Xstart,
			double Xstep, String geneNames[]) {
		XYSeriesCollection dataset = new XYSeriesCollection();
		for (int gene = 0; gene < expData.length; ++gene) {
			XYSeries series;
			if (geneNames == null) {
				series = new XYSeries("Gene " + (gene + 1));
			} else {
				series = new XYSeries(geneNames[gene]);
			}
			double t = Xstart;
			for (int sample = 0; sample < expData[gene].length; ++sample, t += Xstep) {
				series.add(t, expData[gene][sample]);
			}
			dataset.addSeries(series);
		}
		return dataset;
	}

	/**
	 * Starting point for the demonstration application.
	 * 
	 * @param args
	 *            ignored.
	 */
	/*
	 * /** Creates a sample dataset.
	 * 
	 * @return A dataset.
	 */
	/*
	 * private XYDataset createSampleDataset() { XYSeries series1 = new
	 * XYSeries("Series 1"); series1.add(1.0, 3.3); series1.add(2.0, 4.4);
	 * series1.add(3.0, 1.7); XYSeries series2 = new XYSeries("Series 2");
	 * series2.add(1.0, 7.3); series2.add(2.0, 6.8); series2.add(3.0, 9.6);
	 * series2.add(4.0, 5.6); XYSeriesCollection dataset = new
	 * XYSeriesCollection(); dataset.addSeries(series1);
	 * dataset.addSeries(series2); return dataset; }
	 */

	static class CustomLabelGenerator extends
			AbstractCategoryItemLabelGenerator implements XYItemLabelGenerator {

		private String[] labels;

		public CustomLabelGenerator(String labelFormat, NumberFormat formatter,
				String[] labels) {
			this(labelFormat, formatter);
			this.labels = labels;
		}

		protected CustomLabelGenerator(String labelFormat,
				NumberFormat formatter) {
			super(labelFormat, formatter);
			// TODO Auto-generated constructor stub
		}

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		@Override
		public String generateLabel(XYDataset arg0, int arg1, int arg2) {
			// TODO Auto-generated method stub
			return labels[arg2];
		}

	}

	@Override
	public void stateChanged(ChangeEvent e) {
		JSlider source = (JSlider) e.getSource();
		// if (!source.getValueIsAdjusting()) {
		int i = (int) source.getValue();
		System.out.println(i + ":" + indivs[i].fitnessResult.finalResult());
		if (showingPanel != graphs[i]) {
			if (showingPanel != null) {
				showingPanel.setVisible(false);
			}
			graphs[i].setVisible(true);
			showingPanel = graphs[i];
		}
		// }
	}

	@Override
	public void windowActivated(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowClosed(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowClosing(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowDeactivated(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowDeiconified(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowIconified(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowOpened(WindowEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub

	}

}
